package com.cloudfun.msglisten.config;

import com.cloudfun.msglisten.common.constant.RabbitConstants;
import com.cloudfun.msglisten.util.RabbitConfigUtils;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionNameStrategy;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.boot.autoconfigure.amqp.RabbitProperties;
import org.springframework.boot.autoconfigure.amqp.SimpleRabbitListenerContainerFactoryConfigurer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

/**
 * Created by Huqin on 2020/3/30
 */
@Slf4j
@Configuration
public class RabbitConfig {

    @Autowired
    private RabbitProperties properties;

    @Autowired
    private ObjectProvider<ConnectionNameStrategy> connectionNameStrategy;

    @Autowired
    private SimpleRabbitListenerContainerFactoryConfigurer configurer;

    @Bean
    @Primary
    public CachingConnectionFactory connectionFactory() {
        return RabbitConfigUtils.cachingConnectionFactory(properties, connectionNameStrategy);
    }

    @Bean
    @Primary
    public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory) {
        return new RabbitAdmin(connectionFactory);
    }

    @Bean
    @Primary
    public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory(ConnectionFactory connectionFactory) {
        SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
        configurer.configure(factory, connectionFactory);
        return factory;
    }

    @Bean
    public MessageConverter jsonMessageConverter() {
        ObjectMapper mapper = new ObjectMapper();
        mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        return new Jackson2JsonMessageConverter(mapper);
    }

    @Bean
    @Primary
    public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory, RabbitMsgCallback rabbitMsgCallback) {
        RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
        rabbitTemplate.setMessageConverter(jsonMessageConverter());
        rabbitTemplate.setMandatory(true);
        rabbitTemplate.setConfirmCallback(rabbitMsgCallback);
        rabbitTemplate.setReturnCallback(rabbitMsgCallback);
        return rabbitTemplate;
    }

    // 设备状态
    @Bean
    FanoutExchange deviceStatusMsgExchange() {
        return new FanoutExchange(RabbitConstants.Exchange.DEVICE_STATUS);
    }

    // 设备上下线
    @Bean
    FanoutExchange deviceEventMsgExchange() {
        return new FanoutExchange(RabbitConstants.Exchange.DEVICE_EVENT);
    }

    // 设备告警
    @Bean
    FanoutExchange deviceFaultMsgExchange() {
        return new FanoutExchange(RabbitConstants.Exchange.DEVICE_FAULT);
    }

    //设备信息
    @Bean
    FanoutExchange deviceFirmwareMsgExchange() {
        return new FanoutExchange(RabbitConstants.Exchange.DEVICE_FIRMWARE);
    }

    // 开通数据订阅
    @Bean
    public Queue userActivateDataSubQueue() {
        return new Queue(RabbitConstants.Queue.USER_ACTIVATE_DATA_SUB_MSG_LISTEN, true);
    }

    // 设备消息发送到消息订阅服务
    @Bean
    public Queue deviceMsgToExternalQueue() {
        return new Queue(RabbitConstants.Queue.DEVICE_MSG_TO_EXTERNAL_MSG_LISTEN, true);
    }

    // 所有声明的queue\exchange\binding都使用内部的rabbitAdmin来声明
    @Bean
    BeanPostProcessor beanPostProcessor() {
        return new BeanPostProcessor() {
            @Override
            public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
                if (bean instanceof AbstractDeclarable) {
                    AbstractDeclarable declarable = (AbstractDeclarable) bean;
                    declarable.setAdminsThatShouldDeclare(rabbitAdmin(connectionFactory()));
                }
                return bean;
            }
        };
    }

}
